package com.spark.async.handler;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * AsyncUncaughtExceptionHandler 只能拦截返回类型非 Future 的异步调用方法。通过看
 * AsyncExecutionAspectSupport#handleError(Throwable ex, Method method, Object... params) 的源码，可以很容易得到这个结论，
 * // AsyncExecutionAspectSupport.java
 *
 * protected void handleError(Throwable ex, Method method, Object... params) throws Exception {
 *     // 重点！！！如果返回类型是 Future ，则直接抛出该异常。
 *     if (Future.class.isAssignableFrom(method.getReturnType())) {
 *         ReflectionUtils.rethrowException(ex);
 *     } else {
 *         // 否则，交给 AsyncUncaughtExceptionHandler 来处理。
 *         // Could not transmit the exception to the caller with default executor
 *         try {
 *             this.exceptionHandler.obtain().handleUncaughtException(ex, method, params);
 *         } catch (Throwable ex2) {
 *             logger.warn("Exception handler for async method '" + method.toGenericString() +
 *                     "' threw unexpected exception itself", ex2);
 *         }
 *     }
 * }
 *
 * 所以哟，返回类型为 Future 的异步调用方法，需要通过「异步回调」来处理。
 */
@Component
public class GlobalAsyncExceptionHandler implements AsyncUncaughtExceptionHandler {

    private Logger logger = LoggerFactory.getLogger(getClass());

    @Override
    public void handleUncaughtException(Throwable ex, Method method, Object... params) {
        logger.error("[handleUncaughtException][method({}) params({}) 发生异常]",
                method, params, ex);
    }

}